import { hasChanged, isArray, isObject } from "../utils/utility"
import { track, trigger } from "./effect"

export function reactive(target) {
    if (!isObject(target)) {
        return target
    }
    if (isReactive(target)) {
        return target
    }
    if (proxyMap.has(target)) {
        return proxyMap.get(target)
    }

    const proxy = new Proxy(target, {
        get(target, key, receiver) {
            if (key === '__isReactive') {
                return true
            }
            const res = Reflect.get(target, key, receiver)
            track(target, key)
            return isObject(res) ? reactive(res) : res
        },
        set(target, key, value, receiver) {
            const oldValue = target[key]
            let oldLength = target.length
            const res = Reflect.set(target, key, value, receiver)
            if (hasChanged(oldValue, value)) {
                trigger(target, key)
                if (isArray(target) && hasChanged(oldLength, target.length)) {
                    trigger(target, "length")
                }
            }
            return res
        }
    })

    proxyMap.set(target, proxy)

    return proxy
}

// 下面处理一些特例状况

// 1. reactive(reactive(target))
// 判断一个target是否已经被代理过
export function isReactive(target) {
    return !!(target && target.__isReactive)
}

// 2. 代理同一个对象：
// let a = reactive(obj), b = reactive(obj)
// 建立代理表，防止反复代理
const proxyMap = new WeakMap()

// 3. HasChanged
// 确保仅在修改时触发
// 在set函数中，首先取出旧值进行判断

// 4. 深层对象代理
// 在get函数中，对被依赖属性递归处理

// 5. 数组
// 在触发时检测数组的属性

// 6. 嵌套effect
// 在effect中建立函数调用栈，每次返回到上一级函数